﻿using log4net;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using GetOSChinaData.Model;

namespace GetOSChinaData
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// 服务器地址
        /// </summary>
        public static string SERVER_URL = ConfigurationManager.AppSettings["ServerUrl"];

        /// <summary>
        /// 更新服务器数据
        /// </summary>
        public static string getUrl = SERVER_URL + "/project/get";

        /// <summary>
        /// 获取服务器返回数据
        /// </summary>
        public static string listUrl = SERVER_URL + "/project/list";

        /// <summary>
        /// 软件项目 详情 在 oschina 的链接地址
        /// </summary>
        public static string projectDetailUrl = "https://zb.oschina.net/project/detail.html?id={0}";

        /// <summary>
        /// 客户 详情 在 oschina 的链接地址
        /// </summary>
        public static string profileDetailUrl = "https://zb.oschina.net/profile/index.html?u={0}&t=p";

        /// <summary>
        /// 悬赏任务 详情 在 oschina 的链接地址
        /// </summary>
        public static string rewardDetailUrl = "https://zb.oschina.net/reward/detail.html?id={0}";

        /// <summary>
        /// 软件项目
        /// </summary>
        private List<ProjectDetail> projectList = new List<ProjectDetail>();

        /// <summary>
        /// 悬赏任务
        /// </summary>
        private List<ProjectDetail> rewardList = new List<ProjectDetail>();

        /// <summary>
        /// 最新成交
        /// </summary>
        private List<ProjectConfirmed> confirmedList = new List<ProjectConfirmed>();

        /// <summary>
        /// 异步 抓取数据
        /// </summary>
        private BackgroundWorker worker = new BackgroundWorker();

        /// <summary>
        /// 进度条开始值
        /// </summary>
        private int pbStatusBegin = 1;

        /// <summary>
        /// 进度条结束值
        /// </summary>
        private int pbStatusEnd = 100;

        /// <summary>
        /// 一分钟
        /// </summary>
        private int oneMinute = 60 * 1000;

        /// <summary>
        /// 刷新间隔
        /// </summary>
        private int intervalTime = 1;

        /// <summary>
        /// 刷新间隔 最小值
        /// </summary>
        private int intervalTimeMin = 1;

        /// <summary>
        /// 刷新间隔 最大值
        /// </summary>
        private int intervalTimeMax = 60;

        /// <summary>
        /// 定时器
        /// </summary>
        private Timer timer = new Timer();

        /// <summary>
        /// 定时器运行中
        /// </summary>
        private bool timerIsRun;

        /// <summary>
        /// 日志
        /// </summary>
        private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            log.Info("启动");

            // 获取项目数据
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;
            worker.DoWork += new DoWorkEventHandler(this.GetDataDoWork);
            worker.ProgressChanged += new ProgressChangedEventHandler(this.ProgressChanged);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.GetDataRunWorkerCompleted);
            worker.RunWorkerAsync();

            // 设置刷新间隔时间
            intervalTime = int.Parse(this.labelIntervalTime.Content.ToString()); ;
            timerIsRun = false;
        }

        /// <summary>
        /// 逐级记录错误日志及下一级错误日志
        /// </summary>
        /// <param name="ex"></param>
        private string LogEx(Exception ex, int level = 0)
        {
            string msg = ex.Message;
            if (ex.Data.Count > 0)
            {
                foreach (var kvp in ex.Data.Keys)
                {
                    msg += " " + kvp.ToString();
                }
                foreach (var kvp in ex.Data.Values)
                {
                    msg += " " + kvp.ToString();
                }
            }
            if (ex.InnerException != null)
            {
                msg += LogEx(ex.InnerException, level + 1);
            }

            if (level == 0)
            {
                log.Error(msg);
                log.Debug(ex.StackTrace);
            }

            return msg;
        }

        /// <summary>
        /// 运行定时器
        /// </summary>
        private void RunTimer()
        {
            // 定时刷新
            timer.Elapsed += new ElapsedEventHandler(IntervalDataRefresh);
            timer.Interval = oneMinute * intervalTime;
            timer.Enabled = true;
            timer.Start();
        }

        /// <summary>
        /// 定时刷新
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void IntervalDataRefresh(object sender, ElapsedEventArgs e)
        {
            this.labelRefresh1.Dispatcher.BeginInvoke(new Action(() => this.labelRefresh1.Content = timerIsRun ? "定时器运行中。" : "定时器停止。"));
            this.labelIntervalTime.Dispatcher.BeginInvoke(new Action(() => ResetIntervalTime()));
            this.cbIntervalTime.Dispatcher.BeginInvoke(new Action(() => ResetIntervalStatus()));

            if (timerIsRun) worker.RunWorkerAsync();
        }

        /// <summary>
        /// 重置定时器时间
        /// </summary>
        private void ResetIntervalTime()
        {
            int newIntervalTime = int.Parse(this.labelIntervalTime.Content.ToString());
            if (intervalTime != newIntervalTime)
            {
                timer.Interval = oneMinute * newIntervalTime;
            }
        }

        /// <summary>
        /// 重置定时器运行状态
        /// </summary>
        private void ResetIntervalStatus()
        {
            if (cbIntervalTime.IsChecked == null) return;

            timerIsRun = (bool)cbIntervalTime.IsChecked;
        }

        /// <summary>
        /// 通过 http 请求获取数据
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private string GetResopnseResult(string url)
        {
            string result;

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
            req.Method = "GET";
            req.ContentType = "application/json; charset=UTF-8";
            req.AutomaticDecompression = DecompressionMethods.GZip;
            req.Accept = "*/*";
            req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36";

            req.Headers.Add("X-Requested-With", "XMLHttpRequest");
            req.Headers.Add("Sec-Fetch-Site", "same-origin");
            req.Headers.Add("Sec-Fetch-Mode", "cors");
            req.Headers.Add("Sec-Fetch-Dest", "empty");
            req.Headers.Add("Accept-Encoding", "gzip, deflate, br");
            req.Headers.Add("Accept-Language", "zh-CN,zh;q=0.9");
            req.Headers.Add("Cookie", "_user_behavior_=6ae615fd-0bc6-42ae-83c3-40d45e6922a3; Hm_lvt_a411c4d1664dd70048ee98afe7b28f0b=1610349186; oscid=tEJWbC0flFhBos4jxDeAP6SHqQ76WG%2BoiP7wAekl%2BMiUUE9Tkha73Frc8Z7NsrPVTbTYJHUW4VHU%2Fvmj2Xg3YBP5HersVoxBoGp5v3XgiMjOGgypDAryd3fQlZXtB7x88xn8kLoDP0g%3D; _ga=GA1.2.243800708.1610350079; _gid=GA1.2.827705402.1610350079; accessId=8387c580-a888-11e5-bc38-bb63a4ea0854; im-uid=user-435044; im-sdktoken=null; qimo_seosource_8387c580-a888-11e5-bc38-bb63a4ea0854=%E7%AB%99%E5%86%85; qimo_seokeywords_8387c580-a888-11e5-bc38-bb63a4ea0854=; qimo_xstKeywords_8387c580-a888-11e5-bc38-bb63a4ea0854=; Hm_lvt_87fafd62026b5806ad9ec33968c14763=1610442160,1610453341,1610454846,1610456475; _gat_gtag_UA_131295055_1=1; href=https%3A%2F%2Fzb.oschina.net%2Fprojects%2Flist.html; pageViewNum=47; JSESSIONID=C8E37687D7301ABFF7F2F5F5A2B26C8A; Hm_lpvt_87fafd62026b5806ad9ec33968c14763=1610456509");

            using (HttpWebResponse wr = (HttpWebResponse)req.GetResponse())
            {
                Stream stream = wr.GetResponseStream();
                StreamReader sr = new StreamReader(stream, Encoding.UTF8);
                result = sr.ReadToEnd();
                stream.Close();
                sr.Close();
            }

            return result;
        }

        /// <summary>
        /// 刷新 软件项目 DataGrid
        /// </summary>
        private void dgRJXMDataRefresh()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("ID");
            dt.Columns.Add("姓名");
            dt.Columns.Add("发布时间");
            dt.Columns.Add("更新时间");
            dt.Columns.Add("项目周期");
            dt.Columns.Add("报名", typeof(int));
            dt.Columns.Add("查看", typeof(int));
            dt.Columns.Add("预算");
            dt.Columns.Add("类别");
            dt.Columns.Add("userAccountId");
            dt.Columns.Add("客户");
            dt.Columns.Add("技能");
            dt.Columns.Add("专享");
            dt.Columns.Add("合作倾向");
            dt.Columns.Add("驻场");

            for (int i = 0; i < projectList.Count(); i++)
            {
                DataRow dr = dt.NewRow();
                dr["ID"] = projectList[i].id;
                dr["姓名"] = projectList[i].name;
                dr["发布时间"] = projectList[i].publishTime;
                dr["更新时间"] = projectList[i].statusLastTime;
                dr["项目周期"] = string.Format("{0} {1}", projectList[i].cycle, projectList[i].cycleName);
                dr["报名"] = projectList[i].applyCount;
                dr["查看"] = projectList[i].viewCount;
                dr["预算"] = string.Format("￥{0}-{1}元", projectList[i].budgetMinByYuan, projectList[i].budgetMaxByYuan);
                dr["类别"] = projectList[i].application;
                dr["userAccountId"] = projectList[i].userAccountId;
                dr["客户"] = projectList[i].userAccountNickname;
                dr["技能"] = projectList[i].skills;

                // 专享
                string zx = "";
                if (300 == projectList[i].top) zx = "会员专享";
                if (450 == projectList[i].top) zx = "金牌会员专享";
                dr["专享"] = zx;

                // 合作倾向
                string hzqx = "";
                if ("2" == projectList[i].tendencyType) hzqx = "个人";
                if ("3" == projectList[i].tendencyType) hzqx = "企业";
                hzqx = projectList[i].tendencyProvince + " " + projectList[i].tendencyCity + " " + hzqx;
                hzqx = hzqx.Trim(' ');
                dr["合作倾向"] = hzqx;

                // 驻场
                string zc = "";
                switch (projectList[i].residentRequire)
                {
                    case 2:
                        zc = "偶尔到场交流";
                        break;
                    case 3:
                        zc = "定期驻场";
                        break;
                    case 4:
                        zc = "全程驻场";
                        break;
                }
                dr["驻场"] = zc;

                dt.Rows.Add(dr);
            }
            dgRJXM.ItemsSource = null;
            DataView dv = new DataView(dt)
            {
                Sort = "发布时间 desc"
            };
            dgRJXM.ItemsSource = dv;
        }

        /// <summary>
        /// 刷新 悬赏任务 DataGrid
        /// </summary>
        private void dgXSRWDataRefresh()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("ID");
            dt.Columns.Add("姓名");
            dt.Columns.Add("发布时间");
            dt.Columns.Add("更新时间");
            dt.Columns.Add("项目周期");
            dt.Columns.Add("报名", typeof(int));
            dt.Columns.Add("查看", typeof(int));
            dt.Columns.Add("预算");
            dt.Columns.Add("类别");
            dt.Columns.Add("userAccountId");
            dt.Columns.Add("客户");
            dt.Columns.Add("技能");
            for (int i = 0; i < rewardList.Count(); i++)
            {
                DataRow dr = dt.NewRow();
                dr["ID"] = rewardList[i].id;
                dr["姓名"] = rewardList[i].name;
                dr["发布时间"] = rewardList[i].publishTime;
                dr["更新时间"] = rewardList[i].statusLastTime;
                dr["项目周期"] = rewardList[i].cycleName;
                dr["报名"] = rewardList[i].applyCount;
                dr["查看"] = rewardList[i].viewCount;
                dr["预算"] = "￥" + rewardList[i].budgetMinByYuan;
                dr["类别"] = rewardList[i].application;
                dr["userAccountId"] = rewardList[i].userAccountId;
                dr["客户"] = rewardList[i].userAccountNickname;
                dr["技能"] = rewardList[i].skills;

                dt.Rows.Add(dr);
            }

            dgXSRW.ItemsSource = null;
            DataView dv = new DataView(dt)
            {
                Sort = "发布时间 desc"
            };
            dgXSRW.ItemsSource = dv;
        }

        /// <summary>
        /// 刷新 最新成交 DataGrid
        /// </summary>
        private void dgZXCJDataRefresh()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("项目");
            dt.Columns.Add("预算");
            dt.Columns.Add("开发商");
            for (int i = 0; i < confirmedList.Count(); i++)
            {
                DataRow dr = dt.NewRow();
                dr["项目"] = confirmedList[i].projectName;
                dr["预算"] = confirmedList[i].moneyByYuan;
                dr["开发商"] = confirmedList[i].contractorAccountNickname;
                dt.Rows.Add(dr);
            }

            dgZXCJ.Columns.Clear();
            dgZXCJ.ItemsSource = null;
            DataView dv = new DataView(dt);
            dgZXCJ.ItemsSource = dv;
        }

        /// <summary>
        /// 获取数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GetDataDoWork(object sender, DoWorkEventArgs e)
        {
            ShowProgress("更新数据 开始", pbStatusBegin);

            ShowProgress("更新数据 开始", 5);
            string getResult = string.Empty;
            try
            {
                getResult = GetResopnseResult(getUrl);
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
                ShowProgress("更新数据 出错！", pbStatusEnd);
                return;
            }
            ApiResponse getResponse = JsonConvert.DeserializeObject<ApiResponse>(getResult);
            if (!getResponse.success)
            {
                ShowProgress("更新数据 出错！", pbStatusEnd);
                return;
            }
            ShowProgress("更新数据 完成", 15);

            ShowProgress("读取 软件项目、悬赏任务、最新成交 开始", 25);
            string listResult = string.Empty;
            try
            {
                listResult = GetResopnseResult(listUrl);
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
                ShowProgress("读取 软件项目、悬赏任务、最新成交 出错！", pbStatusEnd);
                return;
            }
            ApiResponse listResponse = JsonConvert.DeserializeObject<ApiResponse>(listResult);
            if (!listResponse.success)
            {
                ShowProgress("读取 软件项目、悬赏任务、最新成交 出错！", pbStatusEnd);
                return;
            }
            ShowProgress("读取 软件项目、悬赏任务、最新成交 完成", 55);

            ShowProgress("绑定 软件项目 开始", 60);
            projectList.RemoveRange(0, projectList.Count);
            projectList.AddRange(listResponse.project_list);
            dgRJXM.Dispatcher.BeginInvoke(new Action(() => dgRJXMDataRefresh()));
            ShowProgress("绑定 软件项目 完成", 75);

            //悬赏任务
            ShowProgress("绑定 悬赏任务 开始", 80);
            rewardList.RemoveRange(0, rewardList.Count);
            rewardList.AddRange(listResponse.reward_list);
            dgXSRW.Dispatcher.BeginInvoke(new Action(() => dgXSRWDataRefresh()));
            ShowProgress("绑定 悬赏任务 完成", 95);

            //最新成交
            ShowProgress("绑定 最新成交 开始", 98);
            confirmedList.RemoveRange(0, confirmedList.Count);
            confirmedList.AddRange(listResponse.confirmed_list);
            dgZXCJ.Dispatcher.BeginInvoke(new Action(() => dgZXCJDataRefresh()));
            ShowProgress("读取 最新成交 完成", 99);

            ShowProgress(
                "更新数据 完成（软件项目："
                + projectList.Count()
                + "，悬赏任务："
                + rewardList.Count()
                + "，最新成交："
                + confirmedList.Count()
                + "）"
                , pbStatusEnd
                );
        }

        /// <summary>
        /// 显示进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ShowProgress((e.UserState == null) ? "" : e.UserState.ToString(), e.ProgressPercentage);
        }

        /// <summary>
        /// 绑定数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GetDataRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
        }

        /// <summary>
        /// 显示进度
        /// </summary>
        /// <param name="strMsg"></param>
        /// <param name="intValue"></param>
        public void ShowProgress(string strMsg, int intValue)
        {
            log.Info(strMsg + "(" + intValue + ")");
            if (intValue == pbStatusBegin)
            {
                pbStatus.Dispatcher.BeginInvoke(new Action(() => pbStatus.Visibility = Visibility.Visible));
            }

            labelStatus.Dispatcher.BeginInvoke(new Action(() => labelStatus.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + strMsg));
            pbStatus.Dispatcher.BeginInvoke(new Action(() => pbStatus.Value = intValue));

            if (intValue == 100)
            {
                pbStatus.Dispatcher.BeginInvoke(new Action(() => pbStatus.Visibility = Visibility.Hidden));
            }
        }

        /// <summary>
        /// 点击项目所在行，通过默认浏览器打开该 软件项目
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgRJXM_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (dgRJXM.SelectedValue != null)
            {
                DataRowView dr = (DataRowView)dgRJXM.SelectedValue;
                System.Diagnostics.Process.Start(string.Format(projectDetailUrl, dr["ID"].ToString()));
            }
        }

        /// <summary>
        /// 查看客户信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgRJXM_HyperlinkClick(object sender, RoutedEventArgs e)
        {
            if (e.OriginalSource != null)
            {
                System.Diagnostics.Process.Start(
                    string.Format(profileDetailUrl, ((Hyperlink)e.OriginalSource).NavigateUri.OriginalString)
                );
            }
        }

        /// <summary>
        /// 点击项目所在行，通过默认浏览器打开该 悬赏任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgXSRW_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (dgXSRW.CurrentItem != null)
            {
                DataRowView dr = (DataRowView)dgXSRW.CurrentItem;
                System.Diagnostics.Process.Start(
                    string.Format(rewardDetailUrl, dr["ID"].ToString())
                );
            }
        }

        /// <summary>
        /// 清空数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRefresh_Click(object sender, RoutedEventArgs e)
        {
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// 减少刷新间隔
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDec_Click(object sender, RoutedEventArgs e)
        {
            int newIntervalTime = int.Parse(this.labelIntervalTime.Content.ToString()) - 1;
            if (newIntervalTime < intervalTimeMin) return;

            this.labelIntervalTime.Content = newIntervalTime.ToString();
        }

        /// <summary>
        /// 增加刷新间隔
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            int newIntervalTime = int.Parse(this.labelIntervalTime.Content.ToString()) + 1;
            if (newIntervalTime > intervalTimeMax) return;

            this.labelIntervalTime.Content = newIntervalTime.ToString();
        }

        /// <summary>
        /// 切换定时器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbIntervalTime_Click(object sender, RoutedEventArgs e)
        {
            if (cbIntervalTime.IsChecked == null) return;

            bool isChecked = (bool)cbIntervalTime.IsChecked;

            if (isChecked && !timerIsRun)
            {
                timerIsRun = true;
                intervalTime = int.Parse(this.labelIntervalTime.Content.ToString());
                RunTimer();
            }

            if (!isChecked && timerIsRun)
            {
                timerIsRun = false;
                timer.Stop();
            }

            string msg;
            if (timerIsRun)
            {
                msg = "定时器已启动，" + intervalTime.ToString() + "分钟后开始刷新数据。";
            }
            else
            {
                msg = "定时器已停止。";
            }
            this.labelRefresh1.Dispatcher.BeginInvoke(new Action(() => this.labelRefresh1.Content = msg));
        }

        /// <summary>
        /// 全局查询
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbSearch_TextChanged(object sender, TextChangedEventArgs e)
        {
            // 软件项目
            SearchContent(dgRJXM, tbSearch.Text);

            // 悬赏任务
            SearchContent(dgXSRW, tbSearch.Text);

            // 最新成交
            SearchContent(dgZXCJ, tbSearch.Text);
        }

        /// <summary>
        /// 在指定的 DataGrid 中进行全局查询
        /// </summary>
        /// <param name="dg"></param>
        /// <param name="condition"></param>
        private void SearchContent(DataGrid dg, string condition)
        {
            string code = string.Empty;
            DataView dv = dg.ItemsSource as DataView;

            for (int i = 0; i < dv.Table.Columns.Count; i++)
            {
                if (dv.Table.Columns[i].DataType == typeof(System.Int32) || dv.Table.Columns[i].DataType == typeof(System.Byte))
                {
                    if (condition.Substring(0, 1) != "0" && Regex.IsMatch(condition, @"^[+-]?\d*[.]?\d*$"))
                    {
                        code += (string)dv.Table.Columns[i].ToString() + " = " + condition + " or ";
                    }
                }
                else if (dv.Table.Columns[i].DataType == typeof(System.DateTime))
                {
                    try
                    {
                        code += (string)dv.Table.Columns[i].ToString() + " = '" + Convert.ToDateTime(condition) + "' or ";
                    }
                    catch (Exception)
                    {
                    }
                }
                else
                {
                    code += (string)dv.Table.Columns[i].ToString() + " like '%" + condition + "%' or ";
                }
            }

            if (!string.IsNullOrEmpty(code))
            {
                code = code.Substring(0, code.Length - 3);
                dv.RowFilter = code;
                dg.ItemsSource = dv;
            }
        }
    }
}
